<template>
  <div class="me-upload">
    <van-uploader
      v-bind="$attrs"
      :max-count="maxCount"
      :max-size="maxSize"
      :before-read="handleBeforeRead"
      :after-read="handleAfterRead"
      @delete="handleDelete"
      v-model="fileList"
    >
      <!-- 自定义上传区域插槽 -->
      <template #default>
        <slot />
      </template>
    </van-uploader>

    <!-- 图片预览 -->
    <van-image-preview
      v-model:show="showPreview"
      :images="previewImages"
      :start-position="previewIndex"
      :show-index="true"
      :closeable="true"
      @close="handlePreviewClose"
    >
      <template #cover>
        <div class="preview-actions">
          <van-icon name="replay" @click="handleRotate" />
          <van-icon name="delete" @click="handlePreviewDelete" />
        </div>
      </template>
    </van-image-preview>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { showToast } from 'vant'
import type { UploaderFileListItem, UploaderBeforeRead, UploaderAfterRead } from 'vant'
import { Api } from '@/api'

interface Props {
  modelValue?: UploaderFileListItem[]
  maxCount?: number
  maxSize?: number
  uploadText?: string
  allowedTypes?: string[]
}

// 定义属性
const props = withDefaults(defineProps<Props>(), {
  modelValue: () => [],
  maxCount: 9,
  maxSize: 5 * 1024 * 1024, // 5MB
  uploadText: '上传图片',
  allowedTypes: () => ['image/jpeg', 'image/png', 'image/gif']
})

// 定义事件
const emit = defineEmits<{
  (e: 'update:modelValue', files: UploaderFileListItem[]): void
  (e: 'upload-success', file: UploaderFileListItem): void
  (e: 'upload-error', error: Error): void
}>()

// 文件列表
const fileList = ref<UploaderFileListItem[]>(props.modelValue)

// 预览相关状态
const showPreview = ref(false)
const previewIndex = ref(0)
const currentRotation = ref(0)

// 计算预览图片列表
const previewImages = computed(() => {
  return fileList.value.map(item => item.content || item.url || '')
})

// 监听文件列表变化
watch(fileList, (newVal) => {
  emit('update:modelValue', newVal)
}, { deep: true })

// 上传前校验
const handleBeforeRead: UploaderBeforeRead = (file) => {
  if (Array.isArray(file)) {
    return file.every(f => validateFile(f))
  }
  return validateFile(file)
}

const validateFile = (file: File) => {
  // 检查文件类型
  if (!props.allowedTypes.includes(file.type)) {
    showToast('不支持的文件类型')
    return false
  }

  // 检查文件大小
  if (file.size > props.maxSize) {
    showToast(`文件大小不能超过${props.maxSize / 1024 / 1024}MB`)
    return false
  }

  return true
}

// 上传后处理
const handleAfterRead: UploaderAfterRead = async (file) => {
  if (Array.isArray(file)) {
    await Promise.all(file.map(f => uploadFile(f)))
  } else {
    await uploadFile(file)
  }
}

const uploadFile = async (file: UploaderFileListItem) => {
  try {
    const formData = new FormData()
    formData.append('file', file.file as File)
    const response = await Api.uploadFile(formData)
    file.url = response.data.url
    emit('upload-success', file)
  } catch (error) {
    emit('upload-error', error as Error)
    showToast('上传失败')
  }
}

// 删除文件
const handleDelete = (file: UploaderFileListItem) => {
  const index = fileList.value.indexOf(file)
  if (index !== -1) {
    fileList.value.splice(index, 1)
  }
}

// 预览相关方法
const handlePreview = (file: UploaderFileListItem) => {
  const index = fileList.value.indexOf(file)
  if (index !== -1) {
    previewIndex.value = index
    showPreview.value = true
  }
}

const handlePreviewClose = () => {
  showPreview.value = false
  currentRotation.value = 0
}

const handleRotate = () => {
  currentRotation.value = (currentRotation.value + 90) % 360
  const img = document.querySelector('.van-image-preview img') as HTMLElement
  if (img) {
    img.style.transform = `rotate(${currentRotation.value}deg)`
  }
}

const handlePreviewDelete = () => {
  handleDelete(fileList.value[previewIndex.value])
  showPreview.value = false
}

// 暴露方法给父组件
defineExpose({
  fileList,
  preview: handlePreview,
  clear: () => {
    fileList.value = []
  }
})
</script>

<style lang="less" scoped>
.me-upload {
  .upload-trigger {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    padding: 16px;
    background: #f7f8fa;
    border-radius: 8px;

    .upload-text {
      margin-top: 8px;
      font-size: 14px;
      color: #666;
    }
  }

  .preview-actions {
    position: absolute;
    bottom: 16px;
    left: 0;
    right: 0;
    display: flex;
    justify-content: center;
    gap: 32px;
    z-index: 100;

    .van-icon {
      color: #fff;
      font-size: 24px;
      padding: 8px;
      background: rgba(0, 0, 0, 0.5);
      border-radius: 50%;
      cursor: pointer;

      &:active {
        opacity: 0.8;
      }
    }
  }
}
</style>
